//
// Created by benxb on 2021/12/12.
//

#ifndef BENXDB_LINEAR_INDEX_PAGE_H
#define BENXDB_LINEAR_INDEX_PAGE_H

#include <storage/page.h>
#include <memory>
#include <common/simple_value.h>
#include <cstdint>
#include <vector>

namespace benxdb {

using LinearIndexKey = SimpleValue;
using LinearIndexKeyType = SimpleType;

struct LinearIndexLeafPair {
    LinearIndexKey key;
    record_id_t record_id{};
    /**
     * Construct LinearIndexLeafPair
     * @param type key type
     * @param data key data
     * @param rid record id
     */
    LinearIndexLeafPair(LinearIndexKeyType type, const char *data, unsigned long rid) : key(type, data), record_id(rid) {};
    /**
     * Construct LinearIndexLeafPair
     * @param type key type
     * @param data contains key and rid, serialized data
     */
    LinearIndexLeafPair(LinearIndexKeyType type, const char *data);
    LinearIndexLeafPair() = default;
    /**
     * Serialize to storage
     * @param storage
     * @return length
     */
    int SerializeTo(char *storage);

    // Deserialize a value of the given type from the given storage space.
    inline static LinearIndexLeafPair DeserializeFrom(const char *storage, LinearIndexKeyType type);

    // index pair size in bytes
    int GetSize();
    // size of key type
    inline static int SizeOfKeyType(LinearIndexKeyType type);
};

class LinearIndexPage : public Page {
public:
    LinearIndexPage();
    /**
     * Construct LinearIndexPage of certain key type
     * @param type key type
     */
    explicit LinearIndexPage(LinearIndexKeyType type);
    ~LinearIndexPage();

    page_id_t GetPageID();
    void SetPageID(page_id_t page_id);

    uint32_t GetIndexSize();
    void SetIndexSize(uint32_t index_size);

    LinearIndexKeyType GetKeyType();
    void SetKeyType(LinearIndexKeyType type);

    /**
     * Get free slot size for index
     * @return free slot size
     */
    uint32_t GetFreeSlotSize();

    /**
     * Check if it has free slot for inserting new index pair
     * @return true if has free slot
     */
    bool HasFreeSlot();

    /**
     * Check if it has free slot of size index_count
     * @param index_count free slot size
     * @return
     */
    bool HasFreeSlot(int index_count);

    /**
     * Append index pair
     * @param pair
     */
    void AppendIndexPair(LinearIndexLeafPair& pair);

    /**
     * Append many index pairs
     * @param pairs index pairs
     */
    void AppendIndexPairs(std::vector<LinearIndexLeafPair>& pairs);

    /**
     * Get index pair of current position
     * @param index pair index
     * @return index pair
     */
    LinearIndexLeafPair GetIndexPair(int index);

    /**
     * clear index == set index size = 0
     */
    void ClearIndex();

    static int GetHeaderSize() { return HEADER_SIZE; }

private:
    static constexpr int OFFSET_PAGE_ID = 0;
    static constexpr int OFFSET_INDEX_KEY_TYPE = OFFSET_PAGE_ID + sizeof(page_id_t);
    static constexpr int OFFSET_INDEX_SIZE = OFFSET_INDEX_KEY_TYPE + sizeof(LinearIndexKeyType);
    static constexpr int OFFSET_INDEX_BEGIN = OFFSET_INDEX_SIZE + sizeof(uint32_t);
    static constexpr int HEADER_SIZE = OFFSET_INDEX_BEGIN;

    uint32_t GetMaxIndexCount();

    int GetIndexPairSize();
};

}


#endif //BENXDB_LINEAR_INDEX_PAGE_H
